#include<iostream>
#include<string>
class ToKeN{
    enum{INT,CHAR,Double,Str}tok;
    union{
        char cv;
        int iv;
        double dv;
        std::string sv;
    };
public:
    ToKeN():tok(INT),iv(0){}
    ToKeN(const ToKeN&t):tok(t.tok){copyUnion(t);}
    ToKeN&operator=(const ToKeN&);
    ~ToKeN(){if(tok==Str)sv.~basic_string();}
    ToKeN&operator=(const std::string&);
    ToKeN&operator=(char);
    ToKeN&operator=(int);
    ToKeN&operator=(double);
    void copyUnion(const ToKeN&);
    friend std::ostream& operator<<(std::ostream&,const ToKeN&);
};
int main(){
    ToKeN t;
    t=std::string("123");
    std::cout<<t<<std::endl;
}
std::ostream& operator<<(std::ostream&os,const ToKeN&t){
    switch(t.tok){
        case ToKeN::INT:os<<t.iv;break;
        case ToKeN::CHAR:os<<t.cv;break;
        case ToKeN::Double:os<<t.dv;break;
        case ToKeN::Str:os<<t.sv;break;
    }
    return os;
}
ToKeN& ToKeN::operator=(int i){
    if(tok==Str)sv.~basic_string();
    iv=i;
    tok=INT;
    return *this;
}
ToKeN& ToKeN::operator=(char c){
    if(tok==Str)sv.~basic_string();
    cv=c;
    tok=CHAR;
    return *this;
}
ToKeN& ToKeN::operator=(double d){
    if(tok==Str)sv.~basic_string();
    dv=d;
    tok=Double;
    return *this;
}
ToKeN& ToKeN::operator=(const std::string&s){
    if(tok==Str)
        sv=s;
    else
        new(&sv)std::string(s);
    tok=Str;
    return *this;
}
ToKeN& ToKeN::operator=(const ToKeN&t){
    if(tok==Str&&t.tok!=Str)sv.~basic_string();
    else if(tok==Str&&t.tok==Str)
        sv=t.sv;
    else 
        copyUnion(t);
    tok=t.tok;
    return *this;
}
void ToKeN::copyUnion(const ToKeN&t){
    switch(t.tok){
        case ToKeN::INT:iv=t.iv;break;
        case ToKeN::CHAR:cv=t.cv;break;
        case ToKeN::Double:dv=t.dv;break;
        case ToKeN::Str:new(&sv)std::string(t.sv);break;
    }
}